﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.DirectoryServices;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    #endregion

    /// <summary>
    /// Objects that are Contacts
    /// </summary>
    [Serializable]
    public class Contact : ADBaseObjectProperties, IContact {

        #region Members
        #region Fields
        public static readonly new string[] AttributesToGet;

        #region ObjectCategory/ObjectClass identifiers
        public static readonly string ObjectCategoryShortName = "person";
        public static readonly string ObjectClassShortName = "contact";
        #endregion 
        #endregion

        public IExchangeBaseAttributes ExchangeBaseAttributes { get; private set; }

        public IExchangeExtensionAttributes ExchangeExtensionAttributes { get; private set; }

        public ILocationAttributes LocationAttributes { get; private set; }

        /// <summary>
        /// The SMTP email address
        /// </summary>
        public string Mail { get; private set; }

        public IOrganizationAttributes OrganizationAttributes { get; private set; }

        public ITelephoneAttributes TelephoneAttributes { get; private set; }

        #region Name properties

        public string DisplayName { get; protected set; }

        public string GivenName { get; private set; }

        public string Surname { get; private set; }
        #endregion

        #endregion

        #region Constructors
        static Contact() {
            var attributesToGet = new List<string>();

            attributesToGet.AddRange(new string[]
            {
                "displayName",
                "givenName",
                "mail",
                "sn"
            });

            attributesToGet.AddRange(Contoso.ActiveDirectory.OrganizationAttributes.AttributesToGet);
            attributesToGet.AddRange(Contoso.ActiveDirectory.LocationAttributes.AttributesToGet);
            attributesToGet.AddRange(Contoso.ActiveDirectory.TelephoneAttributes.AttributesToGet);
            attributesToGet.AddRange(Contoso.ActiveDirectory.ExchangeBaseAttributes.AttributesToGet);
            attributesToGet.AddRange(Contoso.ActiveDirectory.ExchangeExtensionAttributes.AttributesToGet);
            attributesToGet.AddRange(ADBaseObjectProperties.AttributesToGet);

            AttributesToGet = attributesToGet.Distinct().ToArray();
            attributesToGet = null;
        }

        public Contact() {
            this.Initialize();
        }

        public Contact(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
            if (this.GetType().Name == typeof(Contact).Name) {
                this.Attributes = null;
            }
        }

        public Contact(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
            if (this.GetType().Name == typeof(Contact).Name) {
                this.Attributes = null;
            }
        }

        public Contact(List<string> ldifOutput)
            : base(ldifOutput) {
            if (this.GetType().Name == typeof(Contact).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            base.Initialize();

            this.DisplayName = string.Empty;
            this.GivenName = string.Empty;
            this.Mail = string.Empty;
            this.Surname = string.Empty;

            this.ExchangeBaseAttributes = new ExchangeBaseAttributes();
            this.ExchangeExtensionAttributes = new ExchangeExtensionAttributes();
            this.LocationAttributes = new LocationAttributes();
            this.OrganizationAttributes = new OrganizationAttributes();
            this.TelephoneAttributes = new TelephoneAttributes();
        }
        protected override void ProcessResults() {
            
            try {
                base.ProcessResults();

                if (this.Attributes.ContainsKey("displayName")) this.DisplayName = this.Attributes["displayName"][0].ToString();
                if (this.Attributes.ContainsKey("givenName")) this.GivenName = this.Attributes["givenName"][0].ToString();
                if (this.Attributes.ContainsKey("mail")) this.Mail = this.Attributes["mail"][0].ToString();
                if (this.Attributes.ContainsKey("sn")) this.Surname = this.Attributes["sn"][0].ToString();

                this.LocationAttributes.ProcessResults(this.Attributes);
                this.OrganizationAttributes.ProcessResults(this.Attributes);
                this.TelephoneAttributes.ProcessResults(this.Attributes);
                this.ExchangeBaseAttributes.ProcessResults(this.Attributes);
                this.ExchangeExtensionAttributes.ProcessResults(this.Attributes);

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN) && 
                    this.ObjectClass.Any(x => x.Equals(ObjectCategoryShortName, StringComparison.OrdinalIgnoreCase));

            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", 
                    DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }

            // handle case for blank display name
            if (string.IsNullOrWhiteSpace(this.DisplayName)) {
                if (!string.IsNullOrWhiteSpace(this.Surname)) this.DisplayName += this.Surname;
                if (!string.IsNullOrWhiteSpace(this.GivenName)) this.DisplayName += ", " + this.GivenName;
                if (string.IsNullOrWhiteSpace(this.DisplayName) && !string.IsNullOrWhiteSpace(this.CN)) this.DisplayName = this.CN;
            }
        }
        #endregion
    }
}
